import json
import os

from flask import Blueprint, jsonify, request
import app.admin.models as models
from mlwrite.model import JsonResult
from mlwrite import db
from mlwrite.config import BASE_FOLDER
from .esutils import search_library_text_by_label_id
from concurrent.futures import ThreadPoolExecutor, as_completed
import threading

# from app.admin.utils import categories2tree

bp = Blueprint(name='admin', import_name=__name__, url_prefix='/admin')
json_result = JsonResult(code=0, message='success', data=None)


# 算法引擎列表
@bp.route('/libraryList', methods=['GET'])
def contextual_lib_list():
    parentId = request.args.get('parent_id', default=1)
    conLibLists = models.TContextualLibrary.query.filter(models.TContextualLibrary.group_id == 1).all()
    modules = models.TModules.query.all()
    oneLayer = [sub.to_json() for sub in conLibLists if sub.parent_id == parentId]
    for layer in oneLayer:
        layer['child'] = []
        [layer['child'].append(child.to_json()) for child in conLibLists if
         child.parent_id == layer['id'] and child.label_id not in [module.module_code for module in modules if
                                                                   module.type == 1]]
    result = json_result.success(data=oneLayer)
    return jsonify(result)


@bp.route('/library/<int:id>')
def contextual_one(id):
    con_lib = models.TContextualLibrary.query.filter_by(id=id).first()
    return jsonify(json_result.success(data=con_lib.to_json()))


# @bp.route('/library/<labelId>')
def contextual_label_id(label_id):
    con_lib = models.TContextualLibrary.query.filter_by(label_id=label_id).first()
    return con_lib


@bp.route('/modulesList/<int:type>')
def modules_list(type):
    name = request.args.get('name')
    module_code = request.args.get('module_code')

    modules = models.TModules.query.filter(
        models.TModules.type == type and
        models.TModules.name.like('%' + name + '%') and
        models.TModules.module_code.like(
            '%' + module_code + '%')).all()
    result = [module.to_json() for module in modules]
    for res in result:
        relevancies = models.MlRoute.query.filter(models.MlRoute.contextual_id == res['module_code']) \
            .filter(models.MlRoute.is_delete == 0).all()
        res['relevancy'] = [relevancy.lib_name for relevancy in relevancies]
    res = json_result.success(result)
    return jsonify(res)


@bp.route('/modules/add/<int:_type>', methods=['POST'])
def modules_add(_type):
    params = dict(json.loads(request.data.decode('utf-8')))
    parentId = 0
    if 'parent_id' in params:
        parentId = params['parent_id']
    init_load = 0
    if 'init_load' in params:
        init_load = params['init_load']

    # 续写
    if _type == 2:
        ctxLen = params['ctx_len']
        n_epoch = params['n_epoch']
        batchSize = params['batch_size']
        labelId = params['label_id']
        remark = params['remark']
        con_name = params['con_name']
        change_data = params['relevancy']
        name = con_name + '模型'

        base_path = BASE_FOLDER + 'continued/' + labelId + '/'

        # ensure the instance folder exists
        try:
            os.makedirs(base_path)
        except OSError:
            pass

        module = models.TModules(parent_id=parentId, con_name=con_name, name=name, corpus_determine=0,
                                 epoch_save_frequency=n_epoch, model_level=1, module_code=labelId, type=2,
                                 n_epoch=n_epoch, ctx_len=ctxLen, batch_size=batchSize, remark=remark,
                                 base_path=base_path, init_load=init_load)
        db.session.add(module)
        if len(change_data) > 0:
            db.session.execute(
                models.MlRoute.__table__.insert(),
                [{"lib_key": change['code'], "lib_name": change['name'], "contextual_id": labelId} for change in
                 change_data]
            )
        db.session.commit()
        return jsonify(json_result.success())

    # 语境库
    if _type == 1:
        ctx_len = params['ctx_len']
        n_epoch = params['n_epoch']
        batch_size = params['batch_size']
        label_id = params['label_id']
        remark = params['remark']

        contextual = models.TContextualLibrary.query.filter_by(label_id=label_id).first()
        name = contextual.con_name + '模型'

        base_path = BASE_FOLDER + 'contextual/' + label_id + '/'

        # ensure the instance folder exists
        try:
            os.makedirs(base_path)
        except OSError:
            pass

        module = models.TModules(parent_id=parentId, con_name=contextual.con_name, name=name, corpus_determine=0,
                                 epoch_save_frequency=n_epoch, model_level=1, module_code=label_id, type=1,
                                 n_epoch=n_epoch, ctx_len=ctx_len, batch_size=batch_size, remark=remark,
                                 base_path=base_path, init_load=init_load)

        # routes = models.TLibContextualRoute.query.filter(models.TLibContextualRoute.contextual_id == label_id).all()
        db.session.add(module)
        db.session.commit()
        return jsonify(json_result.success())


@bp.route('/initcorpus/<string:label_id>/<int:_type>')
def init_corpus_data(label_id, _type):
    # with ThreadPoolExecutor(max_workers=3) as pool:
    if _type == 1:
        corpus_base_path = BASE_FOLDER + 'contextual/' + label_id + '/corpus/'
        module = models.TModules.query.filter_by(module_code=label_id).first()
        module.corpus_path = corpus_base_path
        db.session.commit()
        # ensure the instance folder exists
        try:
            os.makedirs(corpus_base_path)
        except OSError:
            pass
        # 通用算法引擎
        if label_id == 'YJtongyzwyj00001':
            pass
            # routes = models.TLibContextualRoute.query \
            #     .filter(models.TLibContextualRoute.is_delete == 0).all()
            # # 排除裁判文书
            # [search_library_text_by_label_id(route.lib_key, corpus_base_path) for route in routes if
            #  route.contextual_id != 'YJcaipwsyz00001']
            # future_list = [pool.submit(search_library_text_by_label_id, route.lib_key, corpus_base_path) for route
            #                in routes if
            #                route.contextual_id != 'YJcaipwsyz00001']
        else:
            routes = models.TLibContextualRoute.query \
                .filter(models.TLibContextualRoute.is_delete == 0) \
                .filter(models.TLibContextualRoute.contextual_id == label_id).all()
            for route in routes:
                search_library_text_by_label_id(route.lib_key, corpus_base_path, contextual=True)
            # future_list = [pool.submit(search_library_text_by_label_id, route.lib_key, corpus_base_path) for route
            #                in routes]
    else:
        corpus_base_path = BASE_FOLDER + 'continued/' + label_id + '/corpus/'
        module = models.TModules.query.filter_by(module_code=label_id).first()
        module.corpus_path = corpus_base_path
        db.session.commit()
        # ensure the instance folder exists
        try:
            os.makedirs(corpus_base_path)
        except OSError:
            pass
        lcrs = models.MlRoute.query \
            .filter(models.MlRoute.is_delete == 0) \
            .filter(models.MlRoute.contextual_id == label_id).all()
        for lcr in lcrs:
            search_library_text_by_label_id(lcr.lib_key, corpus_base_path)
        # future_list = [pool.submit(search_library_text_by_label_id, lcr.lib_key, corpus_base_path) for lcr in lcrs]
    # for future in as_completed(future_list):
    #     result = future.result()  # 获取任务结果
    # 修改模型表
    # module = models.TModules.query.filter_by(module_code=label_id).first()
    # module.corpus_path = corpus_base_path
    # db.session.commit()
    return jsonify(json_result.success(None))


@bp.route('/modules/<int:id>')
def modules_id(id):
    module = models.TModules.query.filter_by(id=id).first()
    return jsonify(json_result.success(module.to_json()))


@bp.route('/modules/update/<int:_id>', methods=['POST'])
def modules_update(_id):
    ctx_len = request.form.get('ctx_len')
    n_epoch = request.form.get('n_epoch')
    batch_size = request.form.get('batch_size')
    con_name = request.form.get('con_name')
    remark = request.form.get('remark')
    init_load = request.form.get('init_load')
    module = models.TModules.query.filter_by(id=_id).first()
    if ctx_len != '' and ctx_len is not None:
        module.ctx_len = ctx_len
    if n_epoch != '' and n_epoch is not None:
        module.n_epoch = n_epoch
    if batch_size != '' and batch_size is not None:
        module.batch_size = batch_size
    if remark != '' and remark is not None:
        module.remark = remark
    if con_name != '' and con_name is not None:
        module.con_name = con_name
    module.init_load = init_load
    db.session.commit()
    return jsonify(json_result.success(None))


@bp.route('/route/<string:label_id>')
def route_byid(label_id):
    lcrs = models.MlRoute.query \
        .filter(models.MlRoute.contextual_id == label_id).all()
    result = [lcr.to_json() for lcr in lcrs]
    return result


@bp.post('/categories')
def lib_categories():
    pid = request.form.get("pid", default=0)
    categories = models.LibCategories.query \
        .filter(models.LibCategories.p_id == pid).all()
    categories_dict = [category.to_json(have_child=True) for category in categories]
    for category in categories_dict:
        category['children'] = []
    return jsonify(json_result.success(data=categories_dict))


@bp.post('/categories/update')
def update_lib_categories():
    params = dict(json.loads(request.data.decode('utf-8')))
    ctxLen = params['ctx_len']
    n_epoch = params['n_epoch']
    batchSize = params['batch_size']
    labelId = params['label_id']
    remark = params['remark']
    con_name = params['con_name']
    change_data = params['relevancy']
    init_load = params['init_load']
    module = models.TModules.query.filter_by(module_code=labelId).first()
    module.ctx_len = ctxLen
    module.n_epoch = n_epoch
    module.batch_size = batchSize
    module.remark = remark
    module.con_name = con_name
    module.init_load = init_load
    if len(change_data) > 0:
        models.MlRoute.query.filter(models.MlRoute.contextual_id == labelId).delete()
        db.session.commit()
        db.session.execute(
            models.MlRoute.__table__.insert(),
            [{"lib_key": change['code'], "lib_name": change['name'], "contextual_id": labelId} for change in
             change_data]
        )
        db.session.commit()
    db.session.commit()
    return jsonify(json_result.success(None))


@bp.route('/module/to/<int:type>')
def to_add_module(type):
    if type == 1:
        print()
    pass


# 定义接口把处理日志并返回到前端
@bp.route('/get_log/<string:label_id>', methods=['GET', 'POST'])
def get_log(label_id):
    from .log import red_logs
    from mlwrite.config import LINE_NUMBER
    model = models.TModules.query.filter_by(models.TModules.module_code == label_id).first()
    _path = model.base_path + 'logs'
    try:
        os.makedirs(_path)
    except OSError:
        pass
    # _path = os.path.dirname(__file__)  # 获取当前文件路径
    log_data = red_logs(_path)  # 获取日志
    # 判断如果此次获取日志行数减去上一次获取日志行数大于0，代表获取到新的日志
    if len(log_data) - LINE_NUMBER[label_id] > 0:
        log_type = 2  # 当前获取到日志
        log_difference = len(log_data) - LINE_NUMBER[label_id]  # 计算获取到少行新日志
        log_list = []  # 存放获取到的新日志
        # 遍历获取到的新日志存放到log_list中
        for i in range(log_difference):
            log_i = log_data[-(i + 1)].decode('utf-8')  # 遍历每一条日志并解码
            log_list.insert(0, log_i)  # 将获取的日志存放log_list中
    else:
        log_type = 3
        log_list = ''
    # 已字典形式返回前端
    _log = {
        'log_type': log_type,
        'log_list': log_list
    }
    # LINE_NUMBER[''] = 0  # 删除上一次获取行数
    LINE_NUMBER[label_id] = (len(log_data))  # 添加此次获取行数
    return _log


def categories2tree(source, parent):
    tree = []
    for item in source:
        if item['p_id'] == parent['id']:
            item['children'] = categories2tree(source, item)
            tree.append(item)
    return tree
